001    /*
002     * Copyright 2005 Stephen J. McConnell.
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.station.server; 
020    
021    import java.net.URI;
022    import java.net.URL;
023    import java.rmi.registry.Registry;
024    
025    import net.dpml.cli.Option;
026    import net.dpml.cli.Group;
027    import net.dpml.cli.CommandLine;
028    import net.dpml.cli.OptionException;
029    import net.dpml.cli.commandline.Parser;
030    import net.dpml.cli.builder.ArgumentBuilder;
031    import net.dpml.cli.builder.GroupBuilder;
032    import net.dpml.cli.builder.DefaultOptionBuilder;
033    import net.dpml.cli.option.PropertyOption;
034    import net.dpml.cli.validation.URIValidator;
035    import net.dpml.cli.validation.NumberValidator;
036    
037    import net.dpml.station.ApplicationRegistry;
038    
039    import net.dpml.transit.Artifact;
040    import net.dpml.transit.model.TransitModel;
041    
042    import net.dpml.util.Logger;
043    
044    /**
045     * The RemoteStation is responsible for the establishment of 
046     * callback monitors to external processes established by the 
047     * station manager.
048     *
049     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
050     * @version 1.0.0
051     */
052    public class StationServerPlugin implements Runnable
053    {
054        private final Logger m_logger;
055        private final CommandLine m_line;
056        private final TransitModel m_model;
057        
058        private RemoteStation m_station;
059        
060       /**
061        * Creation of a new station server plugin for station commandline
062        * handling.
063        * @param logger the assigned logging channel
064        * @param model the transit model
065        * @param args the command line arguments array
066        * @exception Exception if an error occurs
067        */
068        public StationServerPlugin( Logger logger, TransitModel model, String[] args ) throws Exception
069        {
070            m_logger = logger;
071            m_model = model;
072            
073            // parse the command group model
074            
075            Parser parser = new Parser();
076            parser.setGroup( COMMAND_GROUP );
077            try
078            {
079                m_line = parser.parse( args );
080            }
081            catch( OptionException e )
082            {
083                final String message = "Server commandline processing error.";
084                StringBuffer buffer = new StringBuffer( message );
085                buffer.append( "\nArgument count: " + args.length );
086                for( int i=0; i<args.length; i++ )
087                {
088                    buffer.append( "\n  arg (" + i + "): [" + args[i] + "]" );
089                }
090                String error = buffer.toString();
091                throw new Exception( error, e );
092            }
093        }
094        
095       /**
096        * Start the thread.
097        */
098        public void run()
099        {
100            try
101            {
102                int port = getPortValue( m_line, Registry.REGISTRY_PORT );
103                URI uri = (URI) m_line.getValue( URI_OPTION, null );
104                if( null == uri )
105                {
106                    URL url = ApplicationRegistry.DEFAULT_STORAGE_URI.toURL();
107                    m_logger.info( "starting station on port: " + port );
108                    m_station = new RemoteStation( m_logger, m_model, port, url );
109                    Thread.currentThread().setContextClassLoader( ApplicationRegistry.class.getClassLoader() );
110                    setShutdownHook( m_station );
111                }
112                else
113                {
114                    if( Artifact.isRecognized( uri ) )
115                    {
116                        URL url = Artifact.createArtifact( uri ).toURL();
117                        m_logger.info( 
118                        "starting station on port: " 
119                        + port 
120                        + " with registry " 
121                        + url );
122                        m_station = new RemoteStation( m_logger, m_model, port, url );
123                    }
124                    else
125                    {
126                        URL url = uri.toURL();
127                        m_logger.info( 
128                          "starting station on port: " 
129                          + port 
130                          + " with registry " 
131                          + url );
132                        m_station = new RemoteStation( m_logger, m_model, port, url );
133                    }
134                }
135            }
136            catch( Exception e )
137            {
138                final String error = 
139                  "Station startup failure.";
140                m_logger.error( error, e );
141            }
142        }
143        
144        private int getPortValue( CommandLine line, int defaultPort )
145        {
146            if( line.hasOption( PORT_OPTION ) )
147            {
148                Number number = (Number) line.getValue( PORT_OPTION, null );
149                return number.intValue();
150            }
151            else
152            {
153                return defaultPort;
154            }
155        }
156        
157        private URI getRegistryURI( CommandLine line, URI uri )
158        {
159            if( line.hasOption( URI_OPTION ) )
160            {
161                return (URI) line.getValue( URI_OPTION, null );
162            }
163            else
164            {
165                return uri;
166            }
167        }
168    
169       /**
170        * Create a shutdown hook that will trigger shutdown of the station.
171        * @param station the station
172        */
173        public static void setShutdownHook( final RemoteStation station )
174        {
175            Runtime.getRuntime().addShutdownHook( new ShutdownHandler( station ) );
176        }
177        
178        private static final DefaultOptionBuilder OPTION_BUILDER = new DefaultOptionBuilder();
179        private static final ArgumentBuilder ARGUMENT_BUILDER = new ArgumentBuilder();
180        private static final GroupBuilder GROUP_BUILDER = new GroupBuilder();
181    
182        private static final PropertyOption PROPERTY_OPTION = new PropertyOption();
183        private static final NumberValidator NUMBER_VALIDATOR = NumberValidator.getIntegerInstance();
184          
185        private static final Option PORT_OPTION = 
186          ARGUMENT_BUILDER 
187            .withDescription( "Port number." )
188            .withName( "port" )
189            .withMinimum( 0 )
190            .withMaximum( 1 )
191            .withValidator( NUMBER_VALIDATOR )
192            .create();
193            
194        private static final Option URI_OPTION = 
195            OPTION_BUILDER
196              .withShortName( "registry" )
197              .withDescription( "Application registry store." )
198              .withRequired( false )
199              .withArgument(
200                ARGUMENT_BUILDER 
201                  .withDescription( "Local or remote artifact reference." )
202                  .withName( "artifact" )
203                  .withMinimum( 1 )
204                  .withMaximum( 1 )
205                  .withValidator( new URIValidator() )
206                  .create() )
207              .create();
208            
209        private static final Group COMMAND_GROUP =
210          GROUP_BUILDER
211            .withName( "options" )
212            .withOption( PORT_OPTION )
213            .withOption( URI_OPTION )
214            .withOption( PROPERTY_OPTION )
215            .create();
216    
217       /**
218        * Shutdown handler implementation.
219        */
220        private static class ShutdownHandler extends Thread
221        {
222            private final RemoteStation m_station;
223            
224           /**
225            * Creation of a new shutdown handler.
226            * @param station the station to shutdown
227            */
228            ShutdownHandler( final RemoteStation station )
229            {
230                m_station = station;
231            }
232            
233            public void run()
234            {
235                m_station.shutdown();
236            }
237        }
238       
239    }